require("GenCodeCommon")

Gtk224 = Gtk224 or {}
Gtk324 = Gtk324 or {}

-- 此函数格式化GtkTreeStore的数据，FormatGtkTreeStore
function Gtk224.FormatGtkTreeStore(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 还需要读取XML中columns中的内容
    local columns_groups = Gtkui.FormatCommonParentChildsNodeWithIndexValue(ui_data, widget_node, {"columns", "column"})
    if columns_groups == nil or columns_groups[1] == nil then
        print("[ERROR] format GtkTreeStore/GtkListStore fail, missing columns data.")
        return widget_data
    end
    local columns_datas = columns_groups[1]

    -- 校验一下类型？
    if class_name ~= "GtkTreeStore" and class_name ~= "GtkListStore" then
        print("[WARN] format GtkTreeStore/GtkListStore, mismatch class name: " .. widget_data.property.class.value)
    end

    -- 将列转换成属性添加进组件数据中保存
    widget_data.property["column_0"] = {name = "column_0", value = #columns_datas};
    for idx, col in ipairs(columns_datas) do
        -- 循环添加列属性，需要提供一个index值，以供代码生成时使用
        widget_data.property["column_" .. idx] = {name = "column_" .. idx, value = col.type.value}; -- , index = idx
    end
    -- 再添加一个列数量的属性
    widget_data.property["column_count"] = {name = "column_count", value = #columns_datas};

    -- 返回
    return widget_data
end

-- 此函数格式化FormatGtkListStore的数据，FormatGtkListStore
function Gtk224.FormatGtkListStore(ui_data, widget_node, class_name, id_value)
    local fmt_func = function (idx, attr_name, attr_value, type_)
        if type_ == "key" then
            return idx
        else
            -- 添加一个属性
            attr_value.__value__ = attr_name
            -- 返回之
            return attr_value
        end
    end
    -- 先使用FormatGtkTreeStore的格式化函数取得当前UI文件的数据、列数据描述
    local widget_data = Gtk224.FormatGtkTreeStore(ui_data, widget_node, class_name, id_value);

    -- 判断是否有data节点
	local data_node = get_gtk_ui_first_child(ui_data, widget_node);
	-- 循环处理每一个属性结点
	while data_node ~= nil do
		-- 取得结点名
		local data_name = get_gtk_ui_node_name(ui_data, data_node);
		-- 比较名字，如果为data，则读取data节点中的内容
		if data_name == "data" then
            -- 还需要读取XML中columns中的内容
            local data_groups = Gtkui.FormatCommonParentChildsNode(ui_data, data_node, {"row", "col"}, fmt_func);
            -- 如果有，则至少有一个数据节点
            if data_groups == nil or data_groups[1] == nil then
                print("[ERROR] format GtkListStore fail, bad data node.")
                return 
            end
            -- 校验一下，要求每个data节点中
            for row_idx, row in ipairs(data_groups) do
                -- 比较一下列的数量是否一致
                if #row == widget_data.property["column_count"].value then
                    -- 最多支持999999列
                    local name_prefix = "data_" .. string.format("%06d", row_idx) 
                    -- 首行为row_idx，最后一列为row_idx
                    local name_val = name_prefix .. "_######"
                    -- 将列转换成属性添加进组件数据中保存
                    widget_data.property[name_val] = {name = name_val, value = row_idx};
                    -- 然后循环添加每个单元格的内容
                    for col_idx, col in ipairs(row) do
                        name_val = name_prefix .. string.format("_%06d", col_idx)
                        -- 单元格数据，类型与列类型有关
                        cell_data = {name = name_val, value = col.__value__, id = col.id.value, type = widget_data.property["column_" .. col_idx].value}
                        -- 如果有translatable属性，则添加之
                        if col.translatable ~= nil then
                            cell_data.translatable = col.translatable.value;
                        end
                        -- 根据需要调用补丁函数来调整数据输出格式
                        Gtkui.PatchOneProperyValueToCFormat(cell_data, {__type__ = cell_data.type}, nil)

                        -- 循环添加单元格数据
                        widget_data.property[name_val] = cell_data;
                    end
                    -- 末尾项
                    name_val = name_prefix .. "_======"
                    -- 将列转换成属性添加进组件数据中保存
                    widget_data.property[name_val] = {name = name_val, value = row_idx};
                else
                    print("[ERROR] format GtkListStore fail, bad data node.")
                    break;
                end
            end

            -- 应该只有一个data节点
            break;
        end

		-- 取得下一属性
		data_node = get_gtk_ui_next_child(ui_data, widget_node, data_node);
	end

    return widget_data;
end

-- 此函数格式化GtkNotebook的数据，FormatGtkNotebook
function Gtk224.FormatGtkNotebook(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value)

    -- 对于UI文件没有子child属性的控件，则直接返回
    if widget_data.child == nil then
        return widget_data
    end

    -- 先取出来
    local child_widget  = widget_data.child.widget;
    local child_packing = widget_data.child.packing;
    local child_attrib  = widget_data.child.attribute;

    -- 创建一个table来保存数据
    local new_widget = {}
    local new_packing = {}
    local new_attrib = {}

    -- 依次转化
    local prev_idx = 1
    -- 通过子属性为tab来判断
    for idx, attrib in ipairs(child_attrib) do
        if attrib ~= nil then
            if attrib["type"] == "tab" then
                -- 是tab的，插入到临时表中
                table.insert(new_widget, child_widget[idx])
                table.insert(new_packing, child_packing[idx])
                table.insert(new_attrib, child_attrib[idx])
                -- 修改类名为GtkNotebookLabel
                child_widget[idx].property.class.value = "GtkNotebookLabel"
                -- 判断是否为模板控件
                local packing_data = nil;
                if widget_data.property.id == nil and 
                   widget_data.property.class ~= nil and
                   widget_data.property.parent ~= nil and
                   widget_data.property.parent.value == "GtkNotebook" then
                    packing_data = { parent_id = {name = "parent_id", value = widget_data.property.class.value}}
                else
                    packing_data = { parent_id = {name = "parent_id", value = widget_data.property.id.value}}
                end
                -- 移动当前页面所有的packing数据至其子控件
                for name, info in pairs(child_packing[prev_idx]) do
                    packing_data[name] = info
                end
                child_packing[prev_idx] = {}
                -- 是否需要包括Label的packing数据？
                --for name, info in pairs(child_packing[idx]) do
                --    packing_data[name] = info
                --end
                --child_packing[idx] = {}
                -- 添加子控件
                child_widget[idx].child = {
                    -- 控件属性
                    widget = {child_widget[prev_idx]},
                    -- 此Label的packing属性中，添加一个parent_id属性，内容为GtkNotebook控件的ID
                    packing = {packing_data},
                    -- 相应的attribute为空
                    attribute = {{}}
                };
            end
        end
        -- 不是tab的，则记录其位置
        prev_idx = idx;
    end

    widget_data.child.widget = new_widget
    widget_data.child.packing = new_packing
    widget_data.child.attribute = new_attrib
    -- 返回
    return widget_data
end

-- 此函数格式化GtkLabel的数据，FormatGtkLabel
function Gtk224.FormatGtkLabel(ui_data, widget_node, class_name, id_value)
    local fmt_func = function (idx, attr_name, attr_value, type_)
        if type_ == "key" then
            return attr_value.name.value
        else
            if type(attr_value) =="table" then
                local result = {}
                -- 全部为属性字段，因此，只需要其value
                for key, value in pairs(attr_value) do
                    result[key] = value.value;
                end
                return result
            end
            return attr_value;
        end        
    end
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 然后判断是否有attributes字段

    -- 再从当前节点提取属性数据
    local attributes_groups = Gtkui.FormatCommonParentChildsNode(ui_data, widget_node, {"attributes", "attribute"}, fmt_func);
    -- 检查items_groups是否为空，为空则不需要继续执行
    if attributes_groups == nil then
        return widget_data;
    end
    -- 检查items_groups是否为空，为空则不需要继续执行
    if attributes_groups[1] == nil then
        print("[WARN] format GtkLabel fail, bad attributes data.")
        return widget_data;
    end
    -- 遍历所有的attributes结点并添加至属性节点中。
    widget_data.property["pango_attr_0_start"] = {name = "pango_attr_0_start", value = #attributes_groups};
    -- 双层循环处理，其实通常只有一个groups项
    for _, attribute in ipairs(attributes_groups) do
        for attr_shrt_name, info in pairs(attribute) do
            -- pango属性名称加上前缀，便于统一处理
            local attr_name = "pango_attr_" .. attr_shrt_name
            -- 处理start标签
            if info.start ~= nil then
                widget_data.property[attr_name .. "_1_start"] = { name = attr_name .. "_1_start", value = info.start};
                info.start = nil
            end
            -- 处理end标签
            if info["end"] ~= nil then
                widget_data.property[attr_name .. "_2_end"] = { name = attr_name .. "_2_end", value = info["end"]};
                info["end"] = nil
            end
            -- 添加value的起始标签，代码输出中_0_value需要最先输出
            widget_data.property[attr_name .. "_0_value"] = info;
            widget_data.property[attr_name .. "_0_value"].name = attr_name .. "_0_value";
            -- 添加value的末尾标签，代码输出中_3_value需要最先输出
            widget_data.property[attr_name .. "_3_value"] = {name = attr_name .. "_3_value", value = "0"};;
        end
    end
    widget_data.property["pango_attr_z_end"] = {name = "pango_attr_z_end", value = #attributes_groups};

    -- 返回
    return widget_data
end

-- GtkTreeView不需要提供Format函数

-- 此函数格式化GtkTreeSelection的数据，GtkTreeSelection
function Gtk224.FormatGtkTreeSelection(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    --[[
    -- 由于GtkTreeSelection都是GtkTreeView的子组件，所以不需要这么判断了
    -- 首先，取得父节点
    local parent_node = get_gtk_ui_parent(ui_data, widget_node)
    local attr_data = Gtkui.FormatCommonWidgetAttrSimple(ui_data, parent_node, id_value);
    -- 如果有internal-child属性，则将internal-child属性转移至packing中
    if attr_data["internal-child"] ~= nil then
        -- 添加一个packing属性返回
        widget_data.packing = {["internal-child"] = { name = "internal-child", value = attr_data["internal-child"]} };
    end
    ]]-- 

    widget_data.packing = {internal_child = { name = "internal_child", value = "tree_selection"} };

    -- 返回
    return widget_data
end

-- 此函数格式化GtkTreeViewColumn的数据，GtkTreeViewColumn
function Gtk224.FormatGtkTreeViewColumn(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 然后将GtkTreeViewColumn的属性数据中的expand转移至packing中
    if widget_data.property.expand ~= nil then
        -- 如果存在子组件，则将expand属性转移至子组件的packing中
        if widget_data.child.widget ~= nil and widget_data.child.packing ~= nil then
            -- 这里虽然是使用了循环，实际上应该只有一个子项
            for _, packing_item in ipairs(widget_data.child.packing) do
                packing_item.expand = widget_data.property.expand;
            end
            widget_data.property.expand = nil;
        end
    end

    -- 返回
    return widget_data
end

-- 此函数格式化GtkCellRendererAccel的数据
Gtk224.FormatGtkCellRendererAccel = function (ui_data, widget_node, class_name, id_value)
    local fmt_func = function (idx, attr_name, attr_value, type_)
        if type_ == "key" then
            return attr_value.name.value
        else
            return {name = attr_value.name.value, value = attr_name}
        end        
    end
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 首先，取得父节点
    local parent_node = get_gtk_ui_parent(ui_data, widget_node)

    -- 再从父节点提取属性数据
    local attributes = Gtkui.FormatCommonParentChildsNode(ui_data, parent_node, {"attributes", "attribute"}, fmt_func);
    -- 遍历所有的attributes结点并添加至属性节点中。
    for _, attribute in ipairs(attributes) do
        -- 每个attributes下有多个attribute节点
        for prop_name, property in pairs(attribute) do
            if widget_data.property[prop_name] ~= nil then
                print("[ERROR] same property in widget ".. class_name .. ", property name: " .. prop_name)
            end
            -- 保持属性节点中。
            widget_data.property[prop_name] = property;
        end
    end

    -- 返回
    return widget_data
end;

-- 此函数格式化GtkCellRendererCombo的数据
Gtk224.FormatGtkCellRendererCombo = Gtk224.FormatGtkCellRendererAccel;
-- 此函数格式化GtkCellRendererPixbuf的数据
Gtk224.FormatGtkCellRendererPixbuf = Gtk224.FormatGtkCellRendererAccel;
-- 此函数格式化GtkCellRendererProgress的数据
Gtk224.FormatGtkCellRendererProgress = Gtk224.FormatGtkCellRendererAccel;
-- 此函数格式化GtkCellRendererSpinner的数据
Gtk224.FormatGtkCellRendererSpinner = Gtk224.FormatGtkCellRendererAccel;
-- 此函数格式化GtkCellRendererText的数据
Gtk224.FormatGtkCellRendererText = Gtk224.FormatGtkCellRendererAccel;
-- 此函数格式化GtkCellRendererToggle的数据
Gtk224.FormatGtkCellRendererToggle = Gtk224.FormatGtkCellRendererAccel;

function Gtk224.FormatGtkComboBox(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 对于UI文件没有子child属性的控件，则直接返回
    if widget_data.child == nil or widget_data.child.widget == nil or widget_data.child.attribute == nil then
        return widget_data
    end

    -- 判断子节点，实际应该只有一项
    for idx, child_widget in ipairs(widget_data.child.widget) do
        if widget_data.child.attribute[idx] ~= nil then
            -- 根据是否有is-inter-child，来给此结点添加一个子属性
            local attr = widget_data.child.attribute[idx];
            if attr["internal-child"] ~= nil then
                child_widget.property.internal_child = { name = "internal_child", value = "TRUE"};
                -- 添加packing属性
                widget_data.child.packing[idx].internal_child = { name = "internal_child", value = "NULL"};
                -- 目前支持两种父类，分别是GtkComboBox与GtkCombo
                if class_name == "GtkComboBox" or class_name == "GtkComboBoxEntry" then
                    child_widget.property.class.value = "GtkComboBoxChildEntry";
                elseif class_name == "GtkCombo" then
                    child_widget.property.class.value = "GtkComboChildEntry";
                else
                    print("[ERRO] bad internal-child widget in GtkComboBox/GtkCombo, class: " .. class_name)
                end
            end
        end
    end

    -- 返回
    return widget_data
end

----- GtkComboBoxEntry与GtkComboBox完全相同
Gtk224.FormatGtkComboBoxEntry = Gtk224.FormatGtkComboBox;
Gtk224.FormatGtkCombo = Gtk224.FormatGtkComboBox;

-- 此函数格式化FormatGtkComboBoxText的数据，FormatGtkComboBoxText
function Gtk224.FormatGtkComboBoxText(ui_data, widget_node, class_name, id_value)
    local fmt_func = function(idx, attr_name, attr_value, type_)
        if type_ == "key" then
            return idx
        else
            local result = nil
            -- 填充内容
            if attr_value and attr_value.translatable ~= nil then
                result = {name = string.format("text_item_%u", idx), value = attr_name, translatable = attr_value.translatable.value}
            else
                result = {name = string.format("text_item_%u", idx), value = attr_name}
            end
            -- 转换一下格式
            Gtkui.PatchOneProperyValueToCFormat(result, {__type__ ="gchar*" }, nil)
            return result;
        end
    end
    -- 使用父类的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatWidgetDataByParentClass(ui_data, widget_node, class_name, id_value);

    -- 还需要读取XML中items中的内容
    local items_groups = Gtkui.FormatCommonParentChildsNode(ui_data, widget_node, {"items", "item"}, fmt_func);
    -- 检查items_groups是否为空，为空则不需要继续执行
    if items_groups == nil or items_groups[1] == nil then
        print("[WARN] format GtkComboBoxText fail, bad items data.")
        return widget_data;
    end
    -- 只有一项
    local items_data = items_groups[1]
    -- 遍历items_data，并添加到属性数据中
    for i = 1, #items_data do
        widget_data.property[items_data[i].name] = items_data[i]
    end

    return widget_data;
end

-- 此函数格式化FormatGtkActionGroup的数据，FormatGtkActionGroup
function Gtk224.FormatGtkActionGroup(ui_data, widget_node, class_name, id_value)
    local fmt_func = function(idx, attr_name, attr_value, type_)
        if type_ == "key" then
            -- 只有一项，因此key始终返回1，而idx则是多个group之间在一起的统一索引
            return 1
        else
            if attr_name ~= nil then
                attr_value.label = {name = "label", value = attr_name}
            end
            return attr_value;
        end
    end
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);
    -- 没有子控件时，不需要继续执行
    if widget_data.child == nil or widget_data.child.packing == nil then
        return widget_data
    end

    -- 还需要读取XML中accelerator中的内容
    local accelerators_groups = Gtkui.FormatCommonParentChildsNode(ui_data, widget_node, {"child", "accelerator"}, fmt_func);
    -- 检查accelerators_groups是否为空，为空则不需要继续执行
    if accelerators_groups == nil or accelerators_groups[1] == nil then
        print("[WARN] format GtkActionGroup fail, bad accelerator data.")
        return widget_data;
    end
    -- 项目数需要与子控件个数相等
    if #accelerators_groups ~= #widget_data.child.packing then
        print("[WARN] format GtkActionGroup fail, bad accelerator data[%u, %u].", #accelerators_groups, #widget_data.child.packing)
        return widget_data;
    end

    -- 遍历accelerators_groups，并添加到packing属性数据中
    for i = 1, #accelerators_groups do
        -- 这里正常只有一个数据
        for _, accel_data in pairs(accelerators_groups[i]) do
            GtkUtils.copy_to_left(widget_data.child.packing[i], accel_data)
        end
    end

    return widget_data;
end

-- 此函数格式化FormatGtkIconFactory的数据，FormatGtkIconFactory
function Gtk224.FormatGtkIconFactory(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 还需要读取XML中accelerator中的内容
    local sources_groups = Gtkui.FormatCommonParentChildsNodeWithIndexValue(ui_data, widget_node, {"sources", "source"});
    -- 检查sources_groups是否为空，为空则不需要继续执行
    if sources_groups == nil or sources_groups[1] == nil then
        print("[WARN] format GtkIconFactory fail, bad sources data.")
        return widget_data;
    end

    -- 遍历所有的sources_groups，取得所有的stock-id
    local stock_ids = {};
    local __ids_hash = {};
    for _, sources_group in ipairs(sources_groups) do
        for _, source_data in ipairs(sources_group) do
            -- 如果此个stock-id没有出现过，则加入到stock_ids中
            if __ids_hash[source_data["stock-id"].value] == nil then
                __ids_hash[source_data["stock-id"].value] = 0;
                table.insert(stock_ids, source_data["stock-id"].value);
            end
        end
    end

    -- 检查stock_ids是否为空，为空则不需要继续执行
    if #stock_ids == 0 then
        return widget_data;
    end

    -- 判空一下
    if widget_data.child == nil then
        widget_data.child = {packing = {}, attribute = {}, widget = {}};
    end

    -- 根据stock_ids添加多个GtkIconSet实例
    for idx, stock_id in ipairs(stock_ids) do
        -- 更新__ids_hash
        __ids_hash[stock_id] = idx;

        -- 添加GtkIconSet实例
        widget_data.child.widget[idx] = {
            child = {
                packing = {},
                attribute = {},
                widget = {},
            },
            property = {
                class = {name = "class", value = "GtkIconSet"},
                id = {name = "id", value = Gtkui.request_new_id("GtkIconSet")},
            },
        }
        -- 添加GtkIconSet实例的packing属性
        widget_data.child.packing[idx] = {
            stock_id = {name = "stock_id", value = stock_id},
        }
        -- 添加GtkIconSet实例的attribute属性
        widget_data.child.attribute[idx] = {}
    end

    -- 遍历所有的sources_groups，添加所有的GtkIconSource实例
    for _, sources_group in ipairs(sources_groups) do
        for _, source_data in ipairs(sources_group) do
            local stock_id = source_data["stock-id"].value;
            -- 取得对应的stock_id的索引
            local id_idx = __ids_hash[stock_id];
            -- 取得相应的GtkIconSet实例
            local icon_set = widget_data.child.widget[id_idx]
            -- 取得GtkIconSet实例的子控件个数，source_idx为下一个子控件的索引
            local source_idx = #icon_set.child.widget + 1

            -- 添加GtkIconSource实例
            icon_set.child.widget[source_idx] = {}
            -- 属性数据
            icon_set.child.widget[source_idx].property = source_data;
            -- class属性
            icon_set.child.widget[source_idx].property.class = {name = "class", value = "GtkIconSource"};
            -- id属性
            icon_set.child.widget[source_idx].property.id = {name = "id", value = Gtkui.request_new_id("GtkIconSource")};
            -- 删除stock-id属性
            icon_set.child.widget[source_idx].property["stock-id"] = nil;
            -- 修改icon-name属性，名称改为icon_name
            if icon_set.child.widget[source_idx].property["icon-name"] ~= nil then
                icon_set.child.widget[source_idx].property["icon_name"] = icon_set.child.widget[source_idx].property["icon-name"]
                icon_set.child.widget[source_idx].property["icon_name"].name = "icon_name"
                icon_set.child.widget[source_idx].property["icon-name"] = nil
            end

            -- 添加GtkIconSource实例的packing属性
            icon_set.child.packing[source_idx] = {}
            -- 添加GtkIconSource实例的attribute属性
            icon_set.child.attribute[source_idx] = {}
        end
    end

    return widget_data;
end

-- 此函数格式化FormatGtkSizeGroup的数据，FormatGtkSizeGroup
function Gtk224.FormatGtkSizeGroup(ui_data, widget_node, class_name, id_value)
    -- 通过任意子控件的id获取其根控件
    local function lookup_top_widget(ui_data, child_widget)
        -- TODO，这里暂时返回不正确，待后续再整改吧。
        return child_widget;
    end
    local function loop_lookup_top_widget(ui_data, widgets_groups)
        local top_widget = nil;
        -- 遍历所有的widgets_groups
        for _, widget_groups in ipairs(widgets_groups) do
            -- 遍历每一个widget_groups
            for _, widget in ipairs(widget_groups) do
                -- 检查widget是否为空
                if widget ~= nil and widget.name ~= nil and widget.name.value ~= nil then
                    -- 获取top_widget
                    top_widget = lookup_top_widget(ui_data, widget.name.value);
                    -- 如果top_widget不为空，则返回
                    if top_widget ~= nil then
                        return top_widget;
                    end
                end
            end
        end
        return nil;
    end

    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 还需要读取XML中accelerator中的内容
    local widgets_groups = Gtkui.FormatCommonParentChildsNodeWithIndexValue(ui_data, widget_node, {"widgets", "widget"});
    -- 检查sources_groups是否为空，为空则不需要继续执行
    if widgets_groups == nil or widgets_groups[1] == nil then
        print("[WARN] format GtkSizeGroup fail, bad widgets data.")
        return widget_data;
    end

    -- 根据任意一个控件，查找其根控件，作为top_widget属性
    local top_widget = loop_lookup_top_widget(ui_data, widgets_groups);

    -- top_widget属性
    widget_data.property.top_widget = {name = "top_widget", value = top_widget};
    -- 将所有widgets中的widget添加为属性
    local idx = 1;
    for _, widget_groups in ipairs(widgets_groups) do
        for _, widget in ipairs(widget_groups) do
            if widget ~= nil then
                -- 属性名字
                local widget_name = "widget_" .. idx;
                -- 属性值
                widget_data.property[widget_name] = {name = widget_name, value = widget.name.value};
                -- 下一属性
                idx = idx + 1;
            end
        end
    end
    -- 保存widgets的个数
    widget_data.property.widget_count = {name = "widget_count", value = idx};

    return widget_data;
end

-- 此函数格式化FormatGtkWindow的数据，FormatGtkWindow
function Gtk224.FormatGtkWindow(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 还需要读取XML中accelerator中的内容
    local accel_groups_groups = Gtkui.FormatCommonParentChildsNodeWithIndexValue(ui_data, widget_node, {"accel-groups", "group"});
    -- 检查accel_groups是否为空，为空则不需要继续执行
    if accel_groups_groups == nil or accel_groups_groups[1] == nil then
        print("[WARN] format GtkWindow fail, missing accel-groups data.")
        return widget_data;
    end

    -- 将所有accel-groups中的group添加为属性
    local idx = 1;
    for _, accel_groups in ipairs(accel_groups_groups) do
        for _, accel_group in ipairs(accel_groups) do
            if accel_group ~= nil then
                -- 属性名字
                local accel_group_name = "z_accel_group_" .. idx;
                -- 属性值
                widget_data.property[accel_group_name] = {name = accel_group_name, value = accel_group.name.value};
                -- 下一属性
                idx = idx + 1;
            end
        end
    end

    return widget_data;
end

-- 此函数格式化GtkDialog的数据，FormatGtkDialog
function Gtk224.FormatGtkDialog(ui_data, widget_node, class_name, id_value)
    local function find_internal_child_in_child(child_widget)
        for idx, attr_item in ipairs(child_widget.attribute) do
            if attr_item["internal-child"] ~= nil then
                return idx
            end
        end
        print("[ERROR] Can't found vbox in attribute")
        return 1
    end
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatWidgetDataByParentClass(ui_data, widget_node, class_name, id_value);

    -- 校验一下类型？
    if class_name ~= "GtkDialog" then
        print("[WARN] format GtkDialog, mismatch class name: " .. widget_data.property.class.value)
    end
    -- 从当前子控件中找到VBox的索引，通常为1
    local vbox_idx = find_internal_child_in_child(widget_data.child);

    -- 取出来
    local internal_child_attrib = widget_data.child.attribute;
    if internal_child_attrib[vbox_idx]["internal-child"] ~= "vbox" then
        print("[WARN] format GtkDialog, bad internal-child id: " .. internal_child_attrib[vbox_idx]["internal-child"])
    end

    -- 子控件，然后来查找
    local vbox_child_widget  = widget_data.child.widget[vbox_idx];
    -- 修改子控件的类名，在前头添加GtkDialogChild字样
    vbox_child_widget.property.class.value = "GtkDialogChild" .. vbox_child_widget.property.class.value;
    -- 修改其ID值
    vbox_child_widget.property.id.value = "__" .. widget_data.property.id.value .. "_child_vbox";
    -- 也给vbox中添加一个dialog_id的属性
    vbox_child_widget.property.dialog_id = {name = "dialog_id", value = widget_data.property.id.value};
    -- 给对应的子控件添加一个packing属性，防止生成关联代码
    widget_data.child.packing[vbox_idx]["internal_child"] = {name = "internal_child", value = internal_child_attrib[vbox_idx]["internal-child"]};

    -- 处理响应区的控件：通常应该都是GtkButton控件
    local action_area_idx = find_internal_child_in_child(vbox_child_widget.child)

    -- 处理非action_area_idx控件，给其添加一个information字段
    for idx, _ in ipairs(vbox_child_widget.child.widget) do
        -- 如果有子控件，子控件的packing属性中，需要添加information字段
        if idx ~= action_area_idx then
            vbox_child_widget.child.packing[idx].information = {name = "information", value = "TRUE"};
        end
    end

    -- 取得dialog-action_area1控件
    local action_area_widget = vbox_child_widget.child.widget[action_area_idx]
    -- 修改子控件的类名，在前头添加GtkDialogChild字样
    action_area_widget.property.class.value = "GtkDialogChild" .. action_area_widget.property.class.value;
    -- 修改其ID值
    action_area_widget.property.id.value = "__" .. widget_data.property.id.value .. "_child_action_area";
    -- 也给button_box中添加一个dialog_id的属性
    action_area_widget.property.dialog_id = {name = "dialog_id", value = widget_data.property.id.value};
    -- 给对应的子控件添加一个packing属性，防止生成关联代码
    vbox_child_widget.child.packing[vbox_idx]["internal_child"] = {name = "internal_child", value = vbox_child_widget.child.attribute[action_area_idx]["internal-child"]};

    -- 还需要读取XML中action-widgets中的内容
    local action_widgets_group = Gtkui.FormatCommonParentChildsNodeWithNameValue(ui_data, widget_node, {"action-widgets", "action-widget"})
    -- 默认无action_widgets组件，有的时候则调整一下
    local action_widgets = {}
    if action_widgets_group == nil or action_widgets_group[1] == nil then
        print("[WARN] format GtkDialog fail, missing action_widgets.")
    else
        action_widgets = action_widgets_group[1]
        -- 部分继承自GtkDialog的对话框子类，允许在gtk_hbutton_box下没有子对象
        if action_area_widget.child ~= nil and action_area_widget.child.widget ~= nil then
            -- 扫描gtk_hbutton_box的子项，根据ID匹配一下action_widgets中
            for idx, btn_widget in ipairs(action_area_widget.child.widget) do
                local widget_id = btn_widget.property.id.value
                -- 匹配到时，添加response属性
                if action_widgets[widget_id] ~= nil then
                    if action_widgets[widget_id].response ~= nil then
                        if action_widgets[widget_id].response.value ~= nil  then
                            -- 正常而言，每个Button都有相应的response信息
                            action_area_widget.child.packing[idx].response = {name = "response", value = action_widgets[widget_id].response.value};
                            action_area_widget.child.packing[idx].dialog_id = {name = "dialog_id", value = widget_data.property.id.value};
                        else
                            print("[ERROR] format GtkDialog, bad action_widgets data, response value is nil, widget id: " .. widget_id);
                        end
                    else
                        print("[ERROR] format GtkDialog, bad action_widgets data, response is nil, widget id: " .. widget_id);
                    end
                else
                    print("[ERROR] format GtkDialog, bad action_widgets data, widget id: " .. widget_id);
                end
            end
        end
    end

    -- 返回
    return widget_data
end

-- 防止FormatGtkDialog递归一次函数自己
Gtk224.FormatGtkAboutDialog = function (ui_data, widget_node, class_name, id_value)
    return Gtk224.FormatGtkDialog(ui_data, widget_node, "GtkDialog", id_value)
end

-- 都是简单的调用FormatGtkDialog（传递一个额外参数）
Gtk224.FormatGtkFileChooserDialog = Gtk224.FormatGtkAboutDialog;
Gtk224.FormatGtkFileSelection = Gtk224.FormatGtkAboutDialog;
--Gtk224.FormatGtkInputDialog = Gtk224.FormatGtkAboutDialog;
Gtk224.FormatGtkMessageDialog = Gtk224.FormatGtkAboutDialog;

Gtk224.FormatGtkPageSetupUnixDialog = Gtk224.FormatGtkAboutDialog;
Gtk224.FormatGtkPrintUnixDialog = Gtk224.FormatGtkAboutDialog;
Gtk224.FormatGtkRecentChooserDialog = Gtk224.FormatGtkAboutDialog;

-- 此函数格式化GtkInfoBar的数据，FormatGtkInfoBar
function Gtk224.FormatGtkInfoBar(ui_data, widget_node, class_name, id_value)
    local function find_action_area_in_inter_child(internal_widget_attributes)
        for idx, attr_item in ipairs(internal_widget_attributes) do
            if attr_item["internal-child"] == "action_area" then
                return idx
            end
        end
        print("[ERROR] Can't found action_area in attribute")
        return 1
    end
    local function find_content_area_in_inter_child(internal_widget_attributes)
        for idx, attr_item in ipairs(internal_widget_attributes) do
            if attr_item["internal-child"] == "content_area" then
                return idx
            end
        end
        print("[ERROR] Can't found content_area in attribute")
        return 2
    end
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 校验一下类型？
    if class_name ~= "GtkInfoBar" then
        print("[WARN] format GtkInfoBar, mismatch class name: " .. widget_data.property.class.value)
    end

    -- 还需要读取XML中action-widgets中的内容
    local action_widgets_group = Gtkui.FormatCommonParentChildsNodeWithNameValue(ui_data, widget_node, {"action-widgets", "action-widget"})
    -- 默认无action_widgets组件，有的时候则调整一下
    local action_widgets = {}
    if action_widgets_group == nil or action_widgets_group[1] == nil then
        print("[WARN] format FormatGtkInfoBar fail, missing action_widgets.")
    else
        action_widgets = action_widgets_group[1]
    end

    -- 子控件，然后来查找
    local internal_widget_attributes  = widget_data.child.attribute;

    -- 处理响应区的控件
    local action_area_idx = find_action_area_in_inter_child(internal_widget_attributes)
    -- 处理内容区的控件
    local content_area_idx = find_content_area_in_inter_child(internal_widget_attributes);

    -- 创建一个table来保存数据
    local new_widget = {}
    local new_packing = {}
    local new_attrib = {}

    -- 取得action_area控件
    local gtk_hbutton_box = widget_data.child.widget[action_area_idx]
    -- 部分继承自GtkDialog的对话框子类，在gtk_hbutton_box下没有子对象了
    if gtk_hbutton_box.child ~= nil and gtk_hbutton_box.child.widget ~= nil then
        -- 将gtk_hbutton_box的子项全部添加进new_widget, new_packing, new_attrib
        for idx, btn_widget in ipairs(gtk_hbutton_box.child.widget) do
            -- 转移组件属性信息
            table.insert(new_widget, btn_widget)
            -- 转移组件附加属性信息
            table.insert(new_attrib, gtk_hbutton_box.child.attribute[idx])
            -- 转换组件打包信息
            table.insert(new_packing, gtk_hbutton_box.child.packing[idx]);
            -- 同时，每个子组件的packing属性需要添加一项
            gtk_hbutton_box.child.packing[idx]["action_area"] = {name = "action_area", value = 1};
            local widget_id = btn_widget.property.id.value
            -- 准备转换组件打包信息
            if action_widgets[widget_id] ~= nil and 
               action_widgets[widget_id].response ~= nil and 
               action_widgets[widget_id].response.value ~= nil  then
                -- 正常而言，每个Button都有相应的response信息
                gtk_hbutton_box.child.packing[idx].response = {name = "response", value = action_widgets[widget_id].response.value};
            else
                -- 正常而言，如果没有，则默认为0
                gtk_hbutton_box.child.packing[idx].response = {name = "response", value = 0};
            end
        end
    end
    local gtk_box = widget_data.child.widget[content_area_idx]
    -- 部分继承自GtkDialog的对话框子类，在gtk_hbutton_box下没有子对象了
    if gtk_box.child ~= nil and gtk_box.child.widget ~= nil then
        -- 将gtk_hbutton_box的子项全部添加进new_widget, new_packing, new_attrib
        for idx, btn_widget in ipairs(gtk_box.child.widget) do
            -- 转移组件属性信息
            table.insert(new_widget, btn_widget)
            -- 转移组件附加属性信息
            table.insert(new_attrib, gtk_box.child.attribute[idx])
            -- 转换组件打包信息
            table.insert(new_packing, gtk_box.child.packing[idx]);
            -- 同时，每个子组件的packing属性需要添加一项
            gtk_box.child.packing[idx]["content_area"] = {name = "content_area", value = 1};
        end
    end

    -- 当前控件的子控件，过滤了
    for idx, btn_widget in ipairs(widget_data.child.widget) do
        if idx ~= action_area_idx and idx ~= content_area_idx then
            -- 转移组件属性信息
            table.insert(new_widget, btn_widget)
            -- 转移组件附加属性信息
            table.insert(new_attrib, widget_data.child.attribute[idx])
            -- 转换组件打包信息
            table.insert(new_packing, widget_data.child.packing[idx]);
        end
    end

    -- 调整好了
    widget_data.child.widget = new_widget
    widget_data.child.packing = new_packing
    widget_data.child.attribute = new_attrib

    -- 返回
    return widget_data
end

-- 防止FormatGtkDialog递归一次函数自己
function Gtk224.FormatGtkColorSelectionDialog(ui_data, widget_node, class_name, id_value)
    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtk224.FormatGtkWindow(ui_data, widget_node, "GtkDialog", id_value)
    if widget_data == nil or widget_data.child == nil or widget_data.child.widget == nil then
        print("[WARN] format GtkColorSelectionDialog fail, bad widgets data.")
        return widget_data;
    end

    -- 对相应的ID进行Fix
    for _, widget_ in ipairs(widget_data.child.widget) do
        -- 修正GtkColorSelectionDialog的子控件ID
        widget_.property.id.value = string.gsub(widget_.property.id.value, "-", "_");
    end

    -- 然后依次扫描所有子控件，根据其attribute来进行处理
    for idx, attribute in ipairs(widget_data.child.attribute) do
        -- 如果有internal-child属性，则在其相应的packing上添加一个属性项
        if attribute ~= nil and attribute["internal-child"] ~= nil then
            local widget_ = widget_data.child.widget[idx]
            local new_value = string.gsub(attribute["internal-child"], "_", "-");
            -- 目前是只有四种情况，分别是ok_button/cancel_button/help_button/color_selection
            widget_.property.internal_child = {name = "internal_child", value = new_value };
            -- 根据类型映射子控件的的Class
            if widget_.property.class.value == "GtkButton" then
                widget_.property.class.value = "GtkColorSelDlgButton";
            elseif widget_.property.class.value == "GtkColorSelection" then
                widget_.property.class.value = "GtkColorSelectionInterChild";
            else
                print("[ERRO] bad internal-child widget in FormatGtkColorSelectionDialog, class: " .. widget_.property.class.value)
            end
            -- 对于相应存在internal-child的，需要跳过其父子链接关系
            local packing_ = widget_data.child.packing[idx]
            packing_.internal_child = {name = "internal_child", value = new_value};
        end
    end

    -- 返回
    return widget_data
end

-- 防止FormatGtkDialog递归一次函数自己
function Gtk224.FormatGtkFontSelectionDialog(ui_data, widget_node, class_name, id_value)
    local widget_data = Gtk224.FormatGtkWindow(ui_data, widget_node, "GtkDialog", id_value);
    if widget_data == nil or widget_data.child == nil or widget_data.child.widget == nil then
        print("[WARN] format GtkFontSelectionDialog fail, bad widgets data.")
        return widget_data;
    end

    --[[
    -- 还需要读取XML中action-widgets中的内容
    local action_widgets_group = Gtkui.FormatCommonParentChildsNodeWithNameValue(ui_data, widget_node, {"action-widgets", "action-widget"})
    -- 默认无action_widgets组件，有的时候则调整一下
    local action_widgets = {}
    if action_widgets_group == nil or action_widgets_group[1] == nil then
        print("[WARN] format GtkDialog fail, missing action_widgets.")
        --return widget_data
    else
        action_widgets = action_widgets_group[1]
    end
    ]]--

    -- 对相应的ID进行Fix
    for _, widget_ in ipairs(widget_data.child.widget) do
        -- 修正GtkFontSelectionDialog的子控件ID
        widget_.property.id.value = string.gsub(widget_.property.id.value, "-", "_");
    end

    -- 然后依次扫描所有子控件，根据其attribute来进行处理
    for idx, attribute in ipairs(widget_data.child.attribute) do
        -- 如果有internal-child属性，则在其相应的packing上添加一个属性项
        if attribute ~= nil and attribute["internal-child"] ~= nil then
            local widget_ = widget_data.child.widget[idx]
            -- 因为根据名称
            local new_value = string.gsub(attribute["internal-child"], "-", "_");
            -- 根据类型映射子控件的的Class
            if widget_.property.class.value == "GtkButton" then
                widget_.property.class.value = "GtkFontSelDlgButton";
                -- 目前是只有三种情况，分别是ok_button/apply_button/cancel_button
                widget_.property.internal_child = {name = "internal_child", value = new_value };
            elseif widget_.property.class.value == "GtkFontSelection" then
                widget_.property.class.value = "GtkFontSelectionInterChild";
                -- 目前是只有一种情况，分别是font_selection
                widget_.property.internal_child = {name = "internal_child", value = new_value };
            else
                print("[ERRO] bad internal-child widget in FormatGtkColorSelectionDialog, class: " .. widget_.property.class.value)
            end
            -- 对于相应存在internal-child的，需要跳过其父子链接关系
            local packing_ = widget_data.child.packing[idx]
            packing_.internal_child = {name = "internal_child", value = new_value};
        end
    end

    return widget_data;
end

-- GtkUIManager的处理，读取XML数据，依然格式化，然后保存在一个变量中
function Gtk224.FormatGtkUIManager(ui_data, widget_node, class_name, id_value)
    -- 返回ui结点
    local function get_xml_node_by_name(ui_data, widget_node, name)
		-- 遍历所有的属性节点，查找到action-widgets结点
		local child_node = get_gtk_ui_first_child(ui_data, widget_node);
		-- 循环处理每一个属性结点
		while child_node ~= nil do
			-- 取得结点名
			local node_name = get_gtk_ui_node_name(ui_data, child_node);
            if node_name == name then
                return child_node;
            end

			-- 取得下一属性
			child_node = get_gtk_ui_next_child(ui_data, widget_node, child_node);
		end
		return nil;
    end
    -- 表格形式返回XML的属性结点内容
    local function format_property_node_to_string(ui_data, xml_node)
		local result = "";
		-- 遍历所有的属性节点
		local attr_node = get_gtk_ui_first_property(ui_data, xml_node);
		-- 循环处理每一个属性结点
		while attr_node ~= nil do
			-- 取得结点名
			local attr_name = get_gtk_ui_property_name(ui_data, xml_node, attr_node);
            -- 取得结点值
            local attr_value = get_gtk_ui_property_value(ui_data, xml_node, attr_node);

            -- 插入到列表中
            result = result .. " " .. attr_name .. '=\\"' .. attr_value .. '\\"'

			-- 取得下一属性
			attr_node = get_gtk_ui_next_property(ui_data, xml_node, attr_node);
		end
		return result;
    end
	-- 表格形式返回XML格式结点的内容
	local function format_xml_node_to_string(ui_data, xml_node)
		local result = "";
		-- 遍历所有的属性节点，查找到action-widgets结点
		local child_node = get_gtk_ui_first_child(ui_data, xml_node);
		-- 循环处理每一个属性结点
		while child_node ~= nil do
			-- 取得结点名
			local node_name = get_gtk_ui_node_name(ui_data, child_node);
            result = result .. '\"<' .. node_name;

            -- 遍历并取得属性值
            local property_ = nil;
            if (get_gtk_ui_first_property(ui_data, child_node) ~= nil) then
                result = result .. format_property_node_to_string(ui_data, child_node)
            end
            result = result .. '>\"\n'

            -- 如果有子结点
            local child_ = nil
            if (get_gtk_ui_first_child(ui_data, child_node) ~= nil) then
                result = result .. format_xml_node_to_string(ui_data, child_node)
            end
            -- 添加结束
            result = result .. '\"</' .. node_name ..  '>\"\n'

			-- 取得下一属性
			child_node = get_gtk_ui_next_child(ui_data, xml_node, child_node);
		end
		return result;
	end

    -- 先使用通用的格式化函数取得当前UI文件的数据
    local widget_data = Gtkui.FormatCommonWidget(ui_data, widget_node, class_name, id_value);

    -- 遍历并找到UI结点
    local ui_node = get_xml_node_by_name(ui_data, widget_node, "ui")
    -- 如果没有结点，则直接返回
    if ui_node == nil then
        return widget_data
    end

    -- 读取ui等字段，转化成字符串
    local result_str = format_xml_node_to_string(ui_data, ui_node)
    if result_str ~= nil then
        -- 如果没有子结点，则添加之
        if widget_data.child == nil then
            -- 添加一个空结点
            widget_data.child = {attribute = {}, packing = {}, widget = {}}
        end

        -- 插入一个子控件的attribute
        table.insert(widget_data.child.attribute, {})
        -- 插入一个子控件的packing
        table.insert(widget_data.child.packing, {ui = {name="ui", value="TRUE"}})
        -- 插入一个子控件的property
        table.insert(widget_data.child.widget, {property = {class = {name="class", value="GtkUIManagerChildUI"},
                                                            id = {name="id", value="__" .. widget_data.property.id.value .. "_uistr__"},
                                                            merge_id  = {name="merge_id",  value="<ui>\"\n" .. result_str .. "\"</ui>"}}});
    end

    -- 返回
    return widget_data
end

-- Gtk324部分格式化接口，目前暂时直接从Gtk224中拷贝过来
for key, value in pairs(Gtk224) do
    if string.sub(key,1,string.len("FormatGtk")) == "FormatGtk" then
        if type(value) == "function" then
            Gtk324[key] = value;
        else
            print("[WARN] Skip " .. key .. ", this is not a function[type: ]." .. type(value))
        end
    end
end

